//
//  SKSudokuViewController.m
//  Sudoku
//
//  Created by Richard Hodgkins on 08/09/2012.
//  Copyright (c) 2012 Richard Hodgkins. All rights reserved.
//

#import "SKSudokuViewController.h"

#import "SKBoardView.h"
#import "SKBoard+Helper.h"

#define SECS_IN_MILLIS 1000
#define MIN_IN_MILLIS (SECS_IN_MILLIS * 60)
#define HOURS_IN_MILLIS (MIN_IN_MILLIS * 60)

#define UI_UPDATE_INTERVAL_MILLIS 40

#define ELAPSED_TIME_FORMAT @"%02ld:%02ld:%05.2lf"

#define NAV_START @"Start"
#define NAV_RESET @"Reset"
#define NAV_RESUME @"Resume"
#define NAV_CLEAR @"Clear"

#define TAG_ALERT_RESET 1
#define TAG_ALERT_END_INFO 2

@interface SKSudokuViewController ()

@property (nonatomic, strong) SKBoard *boardObject;
@property (nonatomic, strong) SKBoardView *boardView;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, assign) BOOL gameStarted, pencilMode;

// Right nav button items
@property (nonatomic, strong) UIBarButtonItem *gameStateButton, *pencilButton;

@end

@implementation SKSudokuViewController

- (id)initWithBoard:(SKBoard *) board
{
    self = [super init];
    if (self) {
        // Custom initialization
        self.boardObject = board;
        
        DLog(@"Using board: %@", self.boardObject);
        if ([self boardHasSavedState]) {
           DLog(@"Board has a save state: duration=%lf, state=%@", self.boardObject.duration, self.boardObject.moves);
        }
        
        // Set the title to the board name
        self.title = self.boardObject.name;
        
        // Set navigation right button title relative to the board state
        self.gameStateButton = [[UIBarButtonItem alloc] initWithTitle:[self boardHasSavedState] ? NAV_RESUME : NAV_START style:UIBarButtonItemStylePlain target:self action:@selector(didPressRightNavButton)];
        
        self.pencilButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"pencil.png"] style:UIBarButtonItemStylePlain target:self action:@selector(didPressPencilNavButton)];
        self.pencilButton.enabled = NO;
        
        self.navigationItem.rightBarButtonItems = @[self.pencilButton, self.gameStateButton];
        
        const NSNotificationCenter *notifCen = [NSNotificationCenter defaultCenter];
        // Register for app background/foreground notifications
        [notifCen addObserver:self selector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
        [notifCen addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationDidBecomeActiveNotification object:nil];
    }
    return self;
}

- (void)dealloc
{
    const NSNotificationCenter *notifCen = [NSNotificationCenter defaultCenter];
    // Unregister for app background/foreground notifications
    [notifCen removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
    [notifCen removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}

-(void)viewDidLoad
{
    [super viewDidLoad];
    
    CGRect frame = self.view.bounds;
    frame.origin.y = 0;
    frame.size.height -= self.navigationController.navigationBar.frame.size.height;
    
    // Board view
    self.boardView = [[SKBoardView alloc] initWithBoard:self.boardObject andFrame:frame andDelegate:self];
    self.view = self.boardView;
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    
    if ([self boardHasSavedState]) {
        [self pauseGame];
    } else {
        [self resetGame];
    }
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    
    [self saveState];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return IS_IPAD() || interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return IS_IPAD() ? UIInterfaceOrientationMaskAll : UIInterfaceOrientationMaskAllButUpsideDown;
}

-(BOOL)shouldAutorotate
{
    return YES;
}

#pragma mark - App background/foreground notification methods

- (void)didEnterBackground:(NSNotification *) notification
{
    DLog(@"Entering background");
    
    [self saveState];
}

- (void)willEnterForeground:(NSNotification *) notification
{
    DLog(@"Entering foreground");
        
    if (self.gameStarted) {
        self.date = [NSDate date];
    }
}

#pragma mark - Board delegate

- (void)gameWasCompleted
{
    self.boardObject.duration += -[self.date timeIntervalSinceNow];
    const NSTimeInterval duration = self.boardObject.duration;
    [self.boardObject completed];
    [self showEndGameInfoWithDuration:duration];
}

- (BOOL)isInPencilMode
{
    // Pencil mode is active when a the button is in done mode (to act like a toggle button)
    return self.pencilButton.style == UIBarButtonItemStyleDone;
}

# pragma mark - Saved board state

- (BOOL) boardHasSavedState
{
    return self.boardObject.moves != nil;
}

#pragma mark - Start/stop functions

- (void) startGame
{
    // Set the nav bar button as reset
    self.gameStateButton.title = NAV_RESET;
    
    // Enable the pencil mode button
    self.pencilButton.enabled = YES;
    
    // Reset start time to now
    self.date = [NSDate date];
    
    // Mark game as started
    self.gameStarted = YES;
    
    // Enable the board
    [self.boardView enable];
    
    // Turn screen timeout off
    [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}

- (void) resetGame
{
    // Clear the board state
    self.boardObject.duration = 0;
    self.boardObject.moves = nil;
    
    // Set the nav bar button as start
    self.gameStateButton.title = NAV_START;
    
    // Disable the pencil mode button
    self.pencilButton.enabled = NO;
    
    // Mark game as ended
    self.gameStarted = NO;
    
    // Reset the board
    [self.boardView reset];
    
    // Turn screen timeout on
    [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}

// Pause game ready for resume
-  (void) pauseGame
{
    // Set the nav bar button as resume
    self.gameStateButton.title = NAV_RESUME;
    
    // Disable the pencil mode button
    self.pencilButton.enabled = NO;
    
    // Reset start time to now
    self.date = nil;
    
    // Mark game as started
    self.gameStarted = NO;
    
    // Disable the board
    [self.boardView disable];
    
    // Turn screen timeout on
    [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}

#pragma mark - Right nav button pressed

- (void) didPressRightNavButton
{
    if ([self isInPencilMode]) {
        // If we're in pencil mode just clear all the pencil cells
        [self.boardView clearPencilCells];
    } else {
        // Otherwise try and reset the game
        if (self.gameStarted) {
            [self showAlertView:TAG_ALERT_RESET title:@"Are you sure?" message:@"You will lose your current progress." cancelButtonTitle:@"OK" otherButtonTitles:@"Cancel", nil];
        }
        [self startGame];
    }
}

#pragma mark - Pencil nav button pressed

- (void) didPressPencilNavButton
{
    NSString *gameButtonTitle;
    if ([self isInPencilMode]) {
        self.pencilButton.style = UIBarButtonItemStylePlain;
        gameButtonTitle = NAV_RESET;
    } else {
        self.pencilButton.style = UIBarButtonItemStyleDone;
        gameButtonTitle = NAV_CLEAR;
    }
    // Set the title relative to the current pencil mode
    self.gameStateButton.title = gameButtonTitle;
    [self.boardView setIsInPencilMode:[self isInPencilMode]];
}

#pragma mark - Time functions

- (void) showEndGameInfoWithDuration:(NSTimeInterval) duration
{
    const long elapsedTime = lrint(duration * 1000);
    
    long hours = elapsedTime / HOURS_IN_MILLIS;
    long mins = (elapsedTime - (hours * HOURS_IN_MILLIS)) / MIN_IN_MILLIS;
    NSTimeInterval secs = ((NSTimeInterval) (elapsedTime - (hours * HOURS_IN_MILLIS) - (mins * MIN_IN_MILLIS))) / SECS_IN_MILLIS;
    
    NSString *durationString = [NSString stringWithFormat:ELAPSED_TIME_FORMAT, hours, mins, secs];
    
    [self showAlertView:TAG_ALERT_END_INFO title:@"Game Completed!" message:[NSString stringWithFormat:@"You completed the game in %@", durationString] cancelButtonTitle:@"OK" otherButtonTitles:nil];
}

#pragma mark - Alert view delegate

// Called when a button is clicked. The view will be automatically dismissed after this call returns
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    switch (alertView.tag) {
        case TAG_ALERT_END_INFO:
            [self.navigationController popViewControllerAnimated:YES];
            break;
            
        case TAG_ALERT_RESET:
            if (buttonIndex == alertView.cancelButtonIndex) {
                [self resetGame];
            }
            break;
    }
}

#pragma mark - Save board start

- (void) saveState
{
    if (self.gameStarted) {
        self.boardObject.duration += -[self.date timeIntervalSinceNow];
        [self.boardView saveStateToBoard];
    }
    self.date = nil;
}

@end
